package com.cherry.androidcode.util

import android.Manifest.permission.EXPAND_STATUS_BAR
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.graphics.Color
import android.graphics.Point
import android.os.Build
import android.util.Log
import android.view.*
import android.view.ViewGroup.MarginLayoutParams
import androidx.annotation.ColorInt
import androidx.annotation.NonNull
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission
import androidx.drawerlayout.widget.DrawerLayout
import com.cherry.androidcode.MainApp

/**
 * @author DongMS
 * @date 2019/5/27
 */
object StatusBarUtil {

    private const val TAG_STATUS_BAR = "TAG_STATUS_BAR"
    private const val TAG_OFFSET = "TAG_OFFSET"
    private const val KEY_OFFSET = -123

    /**
     * 获取状态栏高度
     *
     * @return
     */
    val statusBarHeight: Int
        get() {
            val resources = getResource()
            val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
            return resources.getDimensionPixelSize(resourceId)
        }

    val isSupportNavBar: Boolean
        get() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                val wm = MainApp.CONTEXT.getSystemService(Context.WINDOW_SERVICE) as? WindowManager
                        ?: return false
                val display = wm.defaultDisplay
                val size = Point()
                val realSize = Point()
                display.getSize(size)
                display.getRealSize(realSize)
                return realSize.y != size.y || realSize.x != size.x
            }
            val menu = ViewConfiguration.get(MainApp.CONTEXT).hasPermanentMenuKey()
            val back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)
            return !menu && !back
        }

    /**
     * 获取底部虚拟导航栏的高度
     *
     * @return
     */
    val navBarHeight: Int
        get() {
            val res = getResource()
            val resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android")
            return if (resourceId != 0) {
                res.getDimensionPixelSize(resourceId)
            } else {
                0
            }
        }

    fun setStatusBarVisibility(@NonNull activity: Activity, isVisible: Boolean) {
        setStatusBarVisibility(activity.window, isVisible)
    }

    fun setStatusBarVisibility(@NonNull window: Window, isVisible: Boolean) {
        if (isVisible) {
            window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
        } else {
            window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
        }
        setStatusBarViewVisible(window, isVisible)
        setMarginTopEqualStatusBarHeight(window, isVisible)
    }

    private fun setMarginTopEqualStatusBarHeight(window: Window, isVisible: Boolean) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return
        val withTag = window.decorView.findViewWithTag<View>(TAG_OFFSET) ?: return
        setMarginTopEqualStatusBarHeight(withTag, isVisible)
    }

    private fun setMarginTopEqualStatusBarHeight(@NonNull view: View, isVisible: Boolean) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return
        view.tag = TAG_OFFSET
        val haveSetOffset = view.getTag(KEY_OFFSET)
        if (haveSetOffset != null && haveSetOffset as Boolean) return
        val layoutParams = view.layoutParams as MarginLayoutParams
        layoutParams.setMargins(layoutParams.leftMargin,
                if (isVisible) layoutParams.topMargin + statusBarHeight else layoutParams.topMargin - statusBarHeight,
                layoutParams.rightMargin,
                layoutParams.bottomMargin)
        view.setTag(KEY_OFFSET, isVisible)
    }

    private fun setStatusBarViewVisible(window: Window, isVisible: Boolean) {
        val decorView = window.decorView as ViewGroup
        val fakeStatusBarView = decorView.findViewWithTag<View>(TAG_STATUS_BAR) ?: return
        fakeStatusBarView.visibility = if (isVisible) View.VISIBLE else View.GONE
    }

    /**
     * view的marginTop+=状态栏高度
     *
     * @param view
     */
    fun addMarginTopEqualStatusBarHeight(@NonNull view: View) {
        setMarginTopEqualStatusBarHeight(view, true)
    }

    /**
     * view的marginTop-=状态栏高度
     *
     * @param view
     */
    fun subtractMarginTopEqualStatusBarHeight(@NonNull view: View) {
        setMarginTopEqualStatusBarHeight(view, false)
    }

    /**
     * 改变状态栏字体的颜色
     *
     * @param activity
     * @param isLightMode true:深色;false:浅色
     */
    fun setStatusBarLightMode(@NonNull activity: Activity,
                              isLightMode: Boolean) {
        setStatusBarLightMode(activity.window, isLightMode)
    }

    fun setStatusBarLightMode(@NonNull window: Window, isLightMode: Boolean) {
        if (DeviceUtil.isXiaomi()) {
            setXiaomiStatusBar(window, isLightMode)
        } else if (DeviceUtil.isMeizu()) {
            setMeizuStatusBar(window, isLightMode)
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                val decorView = window.decorView
                var vis = decorView.systemUiVisibility
                vis = if (isLightMode) {
                    vis or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
                } else {
                    vis and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
                }
                decorView.systemUiVisibility = vis
            }
        }
    }

    @JvmOverloads
    fun setStatusBarColor(@NonNull activity: Activity,
                          @ColorInt color: Int,
                          isDecor: Boolean = false): View? {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null
        transparentStatusBar(activity)
        return applyStatusBarColor(activity, color, isDecor)
    }

    private fun transparentStatusBar(activity: Activity) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return
        val window = activity.window
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
            val option = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                val vis = window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
                window.decorView.systemUiVisibility = option or vis
            } else {
                window.decorView.systemUiVisibility = option
            }
            window.statusBarColor = Color.TRANSPARENT
        } else {
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
        }
    }


    private fun applyStatusBarColor(activity: Activity,
                                    color: Int,
                                    isDecor: Boolean): View? {
        val parent = if (isDecor)
            activity.window.decorView as ViewGroup
        else
            activity.findViewById<View>(android.R.id.content) as ViewGroup
        var fakeStatusBarView: View? = parent.findViewWithTag(TAG_STATUS_BAR)
        if (fakeStatusBarView != null) {
            if (fakeStatusBarView.visibility == View.GONE) {
                fakeStatusBarView.visibility = View.VISIBLE
            }
            fakeStatusBarView.setBackgroundColor(color)
        } else {
            fakeStatusBarView = createStatusBarView(activity, color)
            parent.addView(fakeStatusBarView)
        }
        return fakeStatusBarView
    }

    private fun createStatusBarView(activity: Activity,
                                    color: Int): View {
        val statusBarView = View(activity)
        statusBarView.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight)
        statusBarView.setBackgroundColor(color)
        statusBarView.tag = TAG_STATUS_BAR
        return statusBarView
    }

    /**
     * DrawerLayout结合沉浸式
     *
     * @param drawer
     * @param fakeStatusBar
     * @param color
     * @param isTop         DrawerLayout是否覆盖状态栏
     */
    fun setStatusBarColor4Drawer(@NonNull drawer: DrawerLayout,
                                 @NonNull fakeStatusBar: View,
                                 @ColorInt color: Int,
                                 isTop: Boolean) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return
        val activity = getActivityByView(fakeStatusBar) ?: return
        transparentStatusBar(activity)
        drawer.fitsSystemWindows = false
        setStatusBarColor(fakeStatusBar, color)
        var i = 0
        val count = drawer.childCount
        while (i < count) {
            drawer.getChildAt(i).fitsSystemWindows = false
            i++
        }
        if (isTop) {
            hideStatusBarView(activity.window)
        } else {
            setStatusBarColor(activity, color, false)
        }
    }

    private fun hideStatusBarView(window: Window) {
        val decorView = window.decorView as ViewGroup
        val fakeStatusBarView = decorView.findViewWithTag<View>(TAG_STATUS_BAR) ?: return
        fakeStatusBarView.visibility = View.GONE
    }

    fun setStatusBarColor(@NonNull fakeStatusBar: View,
                          @ColorInt color: Int) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return
        val activity = getActivityByView(fakeStatusBar) ?: return
        transparentStatusBar(activity)
        fakeStatusBar.visibility = View.VISIBLE
        val layoutParams = fakeStatusBar.layoutParams
        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
        layoutParams.height = statusBarHeight
        fakeStatusBar.setBackgroundColor(color)
    }

    private fun getActivityByView(@NonNull view: View): Activity? {
        var context = view.context
        while (context is ContextWrapper) {
            if (context is Activity) {
                return context
            }
            context = context.baseContext
        }
        Log.e("SwBar", "the view's Context is not an Activity.")
        return null
    }

    /**
     * 通知打开/关闭改变沉浸式状态栏
     *
     * @param isVisible true:打开通知;false:关闭通知
     */
    @RequiresPermission(EXPAND_STATUS_BAR)
    fun setNotificationBarVisibility(isVisible: Boolean) {
        val methodName: String
        if (isVisible) {
            methodName = if (Build.VERSION.SDK_INT <= 16) "expand" else "expandNotificationsPanel"
        } else {
            methodName = if (Build.VERSION.SDK_INT <= 16) "collapse" else "collapsePanels"
        }
        invokePanels(methodName)
    }

    private fun invokePanels(methodName: String) {
        try {
            @SuppressLint("WrongConstant")
            val service = MainApp.CONTEXT.getSystemService("statusbar")
            @SuppressLint("PrivateApi")
            val statusBarManager = Class.forName("android.app.StatusBarManager")
            val expand = statusBarManager.getMethod(methodName)
            expand.invoke(service)
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun setNavBarColor(@NonNull activity: Activity, @ColorInt color: Int) {
        setNavBarColor(activity.window, color)
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun setNavBarColor(@NonNull window: Window, @ColorInt color: Int) {
        window.navigationBarColor = color
    }

    /**
     * 获取底部虚拟导航栏的颜色
     *
     * @param activity
     * @return
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun getNavBarColor(@NonNull activity: Activity): Int {
        return getNavBarColor(activity.window)
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun getNavBarColor(@NonNull window: Window): Int {
        return window.navigationBarColor
    }

    /**
     * 设置底部虚拟导航栏是否可见
     *
     * @param activity
     * @param isVisible
     */
    fun setNavBarVisibility(@NonNull activity: Activity, isVisible: Boolean) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return
        setNavBarVisibility(activity.window, isVisible)

    }

    fun setNavBarVisibility(@NonNull window: Window, isVisible: Boolean) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return
        val decorView = window.decorView as ViewGroup
        var i = 0
        val count = decorView.childCount
        while (i < count) {
            val child = decorView.getChildAt(i)
            val id = child.id
            if (id != View.NO_ID) {
                val resourceEntryName = MainApp.CONTEXT
                        .getResources()
                        .getResourceEntryName(id)
                if ("navigationBarBackground" == resourceEntryName) {
                    child.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
                }
            }
            i++
        }
        val uiOptions = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
        if (isVisible) {
            decorView.systemUiVisibility = decorView.systemUiVisibility and uiOptions.inv()
        } else {
            decorView.systemUiVisibility = decorView.systemUiVisibility or uiOptions
        }
    }

    private fun setXiaomiStatusBar(window: Window, isLightStatusBar: Boolean) {
        val clazz = window.javaClass
        try {
            val layoutParams = Class.forName("android.view.MiuiWindowManager\$LayoutParams")
            val field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE")
            val darkModeFlag = field.getInt(layoutParams)
            val extraFlagField = clazz.getMethod("setExtraFlags", Int::class.javaPrimitiveType, Int::class.javaPrimitiveType)
            extraFlagField.invoke(window, if (isLightStatusBar) darkModeFlag else 0, darkModeFlag)
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    private fun setMeizuStatusBar(window: Window, isLightStatusBar: Boolean) {
        val params = window.attributes
        try {
            val darkFlag = WindowManager.LayoutParams::class.java.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON")
            val meizuFlags = WindowManager.LayoutParams::class.java.getDeclaredField("meizuFlags")
            darkFlag.isAccessible = true
            meizuFlags.isAccessible = true
            val bit = darkFlag.getInt(null)
            var value = meizuFlags.getInt(params)
            if (isLightStatusBar) {
                value = value or bit
            } else {
                value = value and bit
            }
            meizuFlags.setInt(params, value)
            window.attributes = params
            darkFlag.isAccessible = false
            meizuFlags.isAccessible = false
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

}
